package com.eairlv.utils;

import cn.hutool.core.util.ReflectUtil;
import com.eairlv.utils.access.UserInfoArgumentResolver;
import com.eairlv.utils.config.MSInterceptor;
import com.eairlv.utils.scanner.ScannerContent;
import com.eairlv.utils.scanner.WebMvcConfigurationScanner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Import;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;
import java.util.Map;

/**
 * <微服务统一拦截器>目前仅支持addInterceptors()、addResourceHandlers()、addArgumentResolvers()扩展
 * 通过配置总开关可以控制<微服务统一拦截器>是否生效
 * - 如果设置为<关>，继承WebMvcConfigurationSupport的自定义配置子类生效
 * - 如果设置为<开>，继承WebMvcConfigurationSupport的自定义配置子类仅addInterceptors()、addResourceHandlers()、addArgumentResolvers()生效
 * - 如果设置为<开>，如果不想继承WebMvcConfigurationSupport，仅需新创建一个类配置注解：@Import(MSWebMvcConfiguration.class) @Configuration 即可
 * 当然，你如果想要更多的自定义内容，那么推荐你自己重写WebMvcConfigurationSupport子类方法，然后再重载addInterceptors()方法，并首先注入
 * <p>
 * registry.addInterceptor(new MSInterceptor(msInterceptorProperties, restTemplate)).addPathPatterns("/**")，以保证<微服务统一拦截器>最先执行，restTemplate需要支持微服务的方式
 *
 * @author eairlv
 * @description
 * @date 10:02 2019/8/29
 */
@Slf4j
@Import(MSInterceptorConfiguration.class)
@ConditionalOnProperty(prefix = "ms-interceptor", value = "enabled", matchIfMissing = true)
public class MSWebMvcConfiguration implements WebMvcConfigurer {

    private final MSInterceptor msInterceptor;
    private final UserInfoArgumentResolver userInfoArgumentResolver;
    private final WebMvcConfigurationScanner webMvcConfigurationScanner;

    public MSWebMvcConfiguration(MSInterceptor msInterceptor, UserInfoArgumentResolver userInfoArgumentResolver) {
        this.msInterceptor = msInterceptor;
        this.userInfoArgumentResolver = userInfoArgumentResolver;
        webMvcConfigurationScanner = new WebMvcConfigurationScanner();
        webMvcConfigurationScanner.startScanner();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(msInterceptor).addPathPatterns("/**");
        for (Map.Entry<Class<?>, ScannerContent> entry : webMvcConfigurationScanner.classListMap.entrySet()) {
            ReflectUtil.invoke(ReflectUtil.newInstance(entry.getKey()), entry.getValue().getInterceptor(), registry);
        }
        log.info("Interceptors Override");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        for (Map.Entry<Class<?>, ScannerContent> entry : webMvcConfigurationScanner.classListMap.entrySet()) {
            ReflectUtil.invoke(ReflectUtil.newInstance(entry.getKey()), entry.getValue().getResourceHandler(), registry);
        }
        registry.addResourceHandler("/doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/4.10.3/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        log.info("ResourceHandlers Override");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        for (Map.Entry<Class<?>, ScannerContent> entry : webMvcConfigurationScanner.classListMap.entrySet()) {
            ReflectUtil.invoke(ReflectUtil.newInstance(entry.getKey()), entry.getValue().getArgumentResolver(), argumentResolvers);
        }
        argumentResolvers.add(userInfoArgumentResolver);
        log.info("ArgumentResolvers Override");
    }

}
